package main

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"reflect"
)

// http://www.widuu.com/archives/01/929.html

func main() {
	fmt.Println("example of go io...")
	PipeWriter2Example()
}

//copy file from one to another
func CopyExample() {
	r, _ := os.Open("/root/tmp/source.txt")
	w, _ := os.Create("/root/tmp/dest.txt")
	num, ec := io.Copy(w, r)
	if ec != nil {
		fmt.Println("copy error :", ec)
	}
	fmt.Println("copy size :", num)
}

//copy N bytes, not all file
func CopyNExample() {
	r, _ := os.Open("/root/tmp/source.txt")
	w, _ := os.Create("/root/tmp/destN.txt")
	num, ec := io.CopyN(w, r, 5)
	if ec != nil {
		fmt.Println("copyn error :", ec)
	}
	defer r.Close()
	b, _ := ioutil.ReadFile("/root/tmp/descN.txt")
	fmt.Println("read file ", string(b))
	fmt.Println("file size ", num)
}

func ReadAtLeastExample() {
	r, _ := os.Open("/root/tmp/t.sh")
	b := make([]byte, 20)
	defer r.Close()
	var total int
	for {
		n, er := io.ReadAtLeast(r, b, 8)
		if er == nil {
			fmt.Println("read enough data: ", string(b))
		}
		if er == io.ErrUnexpectedEOF {
			fmt.Println("read fewer data: ", string(b[0:n]))
		}
		if er == io.ErrShortBuffer {
			fmt.Println("buf too short")
			os.Exit(1)
		}
		if er == io.EOF {
			fmt.Println("read end total")
			break
		}
		total = total + n
	}
}
func ReadFullExample() {
	r, _ := os.Open("/root/tmp/t")
	b := make([]byte, 20)
	num, er := io.ReadFull(r, b)
	if er == io.EOF {
		fmt.Println("Read end total :", num)
	}
	if er == io.ErrUnexpectedEOF {
		fmt.Println("Read fewer data ", string(b[:num]))
	}
	fmt.Println("Read data :", string(b))
}
func WriteStringExample() {
	fmt.Println("WriteStringExample... os.ModePerm=", os.ModePerm)
	w, _ := os.OpenFile("/root/tmp/t1", os.O_RDWR, os.ModePerm)
	n, er := io.WriteString(w, "hello golang WriteString()")
	if er != nil {
		fmt.Println("write error :", er)
	}
	defer w.Close()

	b, _ := ioutil.ReadFile("/root/tmp/t1")
	fmt.Println("write total : ", n)
	fmt.Println("--->", string(b))
}
func LimitedReaderExample() {
	reader, _ := os.Open("/root/tmp/t1")
	limitedReader := io.LimitedReader{
		R: reader,
		N: 20,
	}
	p := make([]byte, 10)
	var total int
	for {
		n, err := limitedReader.Read(p)
		if err == io.EOF {
			fmt.Println("read total:", total)
			fmt.Println("read value:", string(p))
			break
		}
		total = total + n
	}
}

func PipeReaderExample() {
	r, w := io.Pipe()
	fmt.Println("reader from io.Pipe(): ", reflect.TypeOf(r))
	fmt.Println("writer from io.Pipe(): ", reflect.TypeOf(w))
	r.Close()
	_, err := w.Write([]byte("Hello Pipe"))
	if err == io.ErrClosedPipe {
		fmt.Println("Pipe closed... : ", err)
	}
	fmt.Println("---------------------------")
	r, w = io.Pipe()
	err = errors.New("pipe closed...")
	r.CloseWithError(err)
	_, err = w.Write([]byte("test"))
	if err != nil {
		fmt.Println("write error : ", err)
	}
}

func PipeReader2Example() {
	r, w := io.Pipe()
	go w.Write([]byte("hello pipe."))
	d := make([]byte, 11)
	n, _ := r.Read(d)
	fmt.Println("read : ", string(d))
	fmt.Println("size :", n)
}

func PipeWriterExample() {
	r, w := io.Pipe()
	go w.Write([]byte("hello world"))
	data := make([]byte, 11)
	n, err := r.Read(data)
	w.Close()
	if err == io.EOF {
		fmt.Println("executing read return EOF ")
		fmt.Println("executing read number ", n)
	}
	n, _ = r.Read(data)
	fmt.Println(string(data))
	fmt.Println("next read number=", n)
	fmt.Println("------------------------------------")
	r, w = io.Pipe()
	go w.Write([]byte("hello world"))
	err = errors.New("pip closed manually")
	w.CloseWithError(err)
	data = make([]byte, 10)
	_, err = r.Read(data)
	if err != nil {
		fmt.Println("EOF --> ", err)
	}

}

func PipeWriter2Example() {
	r, w := io.Pipe()
	go w.Write([]byte("hello world"))
	data := make([]byte, 11)
	n, _ := r.Read(data)
	fmt.Println("read : ", string(data))
	fmt.Println("read number: ", n)
}
